﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Windows.Forms;
using XCI.Config;
using XCI.Core;
using XCI.Helper;
using XCI.Sys.Forms;
using XCI.Sys.Model;
using XCI.Sys.Service;
using XCI.Windows;
using XCI.Windows.Forms;
using XCI.Windows.Helper;
using XCI.Windows.Plugin.GridSetting;

namespace XCI.Sys
{
    /// <summary>
    /// 系统默认应用程序接口
    /// <para>
    /// 默认实现了系统应用程序接口，所有函数都是虚函数，可根据业务情况，重新父类函数。
    /// </para>
    /// </summary>
    public class BaseApplication : IApp
    {
        /// <summary>
        /// 读取应用程序配置
        /// <para>
        /// 定义应用程序在启动之初，此函数是启动的第一步执行。
        /// 默认实现是从输出目录下的app.json文件中读取配置信息
        /// </para>
        /// </summary>
        public virtual WinFormSetting GetSetting()
        {
            return ConfigFactory.Default.Get("WinForm", () => new WinFormSetting());
        }

        /// <summary>
        /// 保存应用程序配置
        /// <para>
        /// 当系统配置信息发生变化时，把配置信息保存到输出目录下的app.json文件
        /// </para>
        /// </summary>
        /// <param name="setting">配置对象</param>
        public virtual void SaveSetting(WinFormSetting setting)
        {
            ConfigFactory.Default.Save();
        }

        /// <summary>
        /// 获取表格配置对象
        /// <para>
        /// 系统中对表格控件可以进行属性自定义，此函数返回对象可以对用户保存的配置文件上传到服务器，也可以指定本地模式，不上传到服务器。
        /// </para>
        /// </summary>
        public virtual IGridSetting GetGridSetting()
        {
            //如果没有指定服务器地址,则使用本地模式
            return new DefaultGridSetting(SysRuntime.Setting.GridSettingLocalMode);
        }

        /// <summary>
        /// 获取登陆窗口
        /// <para>
        /// 定义系统登录窗口，如不需要登录，请返回null。
        /// </para>
        /// </summary>
        public virtual Form GetLoginForm()
        {
            return new FrmStandardLogin();
        }

        /// <summary>
        /// 获取主窗口
        /// <para>
        /// 定义系统主界面。不允许为null。
        /// </para>
        /// </summary>
        public virtual Form GetMainForm()
        {
            return new FrmStandardMain();
        }

        /// <summary>
        /// 获取启动屏幕
        /// <para>
        /// 定义系统启动屏幕，必须遵守DevExpress组件启动屏幕规范。
        /// </para>
        /// </summary>
        public virtual Type GetSplashScreen()
        {
            return typeof(FrmSplashScreen);
        }

        /// <summary>
        /// 获取等待窗体
        /// <para>
        /// 定义系统等待窗体，必须遵守DevExpress组件等待窗体规范。
        /// </para>
        /// </summary>
        public virtual Type GetWaitForm()
        {
            return typeof(FrmWait);
        }

        /// <summary>
        /// 获取接口对象
        /// <para>
        /// 定义系统后台通讯接口操作对象,函数返回值实现了在请求服务器时自动添加应用标识、时间戳、token等请求头。
        /// </para>
        /// </summary>
        /// <param name="setting">应用设置</param>
        public virtual WebApi GetApi(WinFormSetting setting)
        {
            return new SysWebApi(setting.Id,
                    setting.ApiUrl,
                    TimeSpan.FromMilliseconds(setting.ApiTimeout),
                    setting.IsDebugMode);
        }


        /// <summary>
        /// 用户登录
        /// <para>
        /// 定义用户登录过程。
        /// </para>
        /// </summary>
        /// <param name="account">账号</param>
        /// <param name="password">密码</param>
        /// <param name="captcha">验证码</param>
        /// <returns>成功返回True</returns>
        public virtual BoolMessage<SysUser> UserLogin(string account, string password, string captcha)
        {
            return UserService.Instance.Login(account, password, captcha);
        }

        /// <summary>
        /// 用户登录成功后触发
        /// </summary>
        public virtual void OnLoginSuccess()
        {
            DicService.Instance.RefreshDicListCache();
        }

        /// <summary>
        /// 验证用户
        /// <para>
        /// 验证用户账号密码是否正确，与登录函数不同的是，此函数只验证账号密码，而用户登录还会有其他安全相关的操作和日志记录。
        /// </para>
        /// </summary>
        /// <param name="account">账号</param>
        /// <param name="password">密码</param>
        /// <param name="captcha">验证码</param>
        /// <returns>成功返回True</returns>
        public virtual BoolMessage UserValid(string account, string password, string captcha)
        {
            return UserService.Instance.ValidUser(account, password, captcha);
        }

        /// <summary>
        /// 获取用户拥有的模块集合
        /// <para>
        /// 获取当前用户拥有的系统模块集合。
        /// </para>
        /// </summary>
        /// <param name="user">用户对象</param>
        public virtual IList<SysModule> GetModules(SysUser user)
        {
            return ModuleService.Instance.SelectListByUserId(user.Id);
        }

        /// <summary>
        /// 客户端与服务端网络测试
        /// <para>
        /// 客户端和服务端进行网络测试。
        /// </para>
        /// </summary>
        public virtual bool Ping()
        {
            return SysService.Instance.Ping();
        }

        /// <summary>
        /// 客户端心跳
        /// <para>
        /// 激活当前用户，保持当前客户端在线。
        /// </para>
        /// </summary>
        /// <param name="id">当前应用或者用户标识</param>
        public virtual bool Active(string id)
        {
            return OnlineUserService.Instance.Active(id);
        }

        /// <summary>
        /// 全局处理异常
        /// <para>
        /// 定义系统全局异常处理，只有用户未处理的异常才会再此统一处理，如果用户在函数中编写try catch，则不会触发此函数。
        /// </para>
        /// </summary>
        /// <param name="e">异常对象</param>
        public virtual void GlobalExceptionProcess(Exception e)
        {
            if (e is ControlValueException)
            {
                return;
            }
            if (e is SocketException se)
            {
                MessageBoxHelper.ShowError(DebugHelper.BuildAllMessage(se));
            }
            else if (e is AggregateException ae)
            {
                ae.Handle(p => true);
                var msg = string.Empty;
                if (ae.InnerException != null && ae.InnerException.GetType().Name.Equals("TaskCanceledException"))
                {
                    msg = "连接到服务器时发生错误，请稍后重试";
                }
                else
                {
                    msg = DebugHelper.BuildAllMessage(ae.InnerExceptions.ToArray());
                }
                MessageBoxHelper.ShowError(msg);
            }
            else if (e is WebApiException || e is BoolMessageFailException || e is BoolMessageValidException)
            {
                MessageBoxHelper.ShowError(e.Message);
            }
            else
            {
                var ef = new FrmException(e);
                ef.ShowDialog();
                ef.Dispose();
            }
            DebugHelper.Catch(e.Message);
        }

    }
}